﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace GDD2_Game3
{
	class Track
	{
        private GameData gameData;
		public List<Wall> Walls { get; private set; }
        public List<FinishLine> Finish { get; private set; }
		public List<PowerUp> PowerUps { get; private set; }
		private const float WALL_WIDTH = 50.0f;
		private const float WALL_HEIGHT = 50.0f;
		public List<List<Wall>> GridWalls { get; set; }
		public FloatBox[,] Grid { get; set; }
		public Vector2 Dimensions { get; private set; }
		public float Width
		{
			get
			{
				return Dimensions.X;
			}
			set
			{
				Dimensions = new Vector2(value, Dimensions.Y);
			}
		}
		public float Height
		{
			get
			{
				return Dimensions.Y;
			}
			set
			{
				Dimensions = new Vector2(Dimensions.X, value);
			}
		}

		public Track(GameData data)
		{
            gameData = data;
			createWalls("../../../map2.txt");
			
			GridWalls = new List<List<Wall>>();
            //Walls = new List<Wall>();

            /*
			//create Walls
			//outside walls
			Walls.Add(new Wall(gameData.ScreenWidth / 2, 25, gameData.ScreenWidth, 50));
			Walls.Add(new Wall(gameData.ScreenWidth / 2, gameData.ScreenHeight - 25, gameData.ScreenWidth, 50));
			Walls.Add(new Wall(25, gameData.ScreenHeight / 2, 50, gameData.ScreenHeight));
			Walls.Add(new Wall(gameData.ScreenWidth - 25 / 2, gameData.ScreenHeight / 2, 50, gameData.ScreenHeight));

			//inner walls
			Walls.Add(new Wall(gameData.ScreenWidth / 2, 225, gameData.ScreenWidth - 400, 50));
			Walls.Add(new Wall(gameData.ScreenWidth / 2, gameData.ScreenHeight - 225, gameData.ScreenWidth, 50));
			Walls.Add(new Wall(225, gameData.ScreenHeight / 2, 50, gameData.ScreenHeight));
			Walls.Add(new Wall(gameData.ScreenWidth - 225 / 2, gameData.ScreenHeight / 2, 50, gameData.ScreenHeight - 400));
            */
            

			Grid = new FloatBox[10, 10];
            GridWalls = new List<List<Wall>>();
			//grid to use for simplifying collisions
			for (int i = 0; i < 10; i++)
			{
				for (int j = 0; j < 10; j++)
				{
					Grid[j, i] = FloatBox.CreateGivenTopLeft(gameData.ScreenDimensions * new Vector2(j, i) / 10.0f, gameData.ScreenDimensions / 10.0f);
				}
			}

			foreach (FloatBox gridPiece in Grid)
			{
				List<Wall> section = new List<Wall>();
				foreach (Wall wall in Walls)
				{
					if (gridPiece.Intersects(wall.Box))
					{
						section.Add(wall);
					}
				}
				if (section.Count != 0)
				{
					GridWalls.Add(section);
				}
			}
		}

		private void createWalls(string filename)
		{
			Walls = new List<Wall>();
            Finish = new List<FinishLine>();
			PowerUps = new List<PowerUp>();

			// reads map from a file
			System.IO.StreamReader reader = new System.IO.StreamReader(filename);

			// keeps track of the current x and y position within the grid of wall pieces
			int x = 0;
			int maxX = 0;
			int y = 0;

			// holds the current character we read from the file
			int c;

			// read all characters from the file one at a time
			while((c = reader.Read()) != -1)
			{
				switch(Convert.ToChar(c))
				{
					case '\n': // new lines denote a new row
						++y;
						maxX = Math.Max(maxX, x);
						x = 0;
						break;
					case '#': // '#' denote wall pieces
						// the "+ 0.5f" thing is because we create FloatBoxes referencing the center
						Walls.Add(new Wall((x + 0.5f) * WALL_WIDTH, (y + 0.5f) * WALL_HEIGHT, WALL_WIDTH, WALL_HEIGHT));
						++x;
						break;
					case '.': // '.' denote empty spaces/the road
						++x;
						break;
                    case '=':
                        Finish.Add(new FinishLine((x + 0.5f) * WALL_WIDTH, (y + 0.5f) * WALL_HEIGHT, WALL_WIDTH, WALL_HEIGHT));
                        ++x;
                        break;
					case 'X':
						PowerUps.Add(new PowerUp((x + 0.5f) * WALL_WIDTH, (y + 0.5f) * WALL_HEIGHT, WALL_WIDTH, WALL_HEIGHT));
						++x;
						break;
					case 'S':
						gameData.Vehicle = new Vehicle((x + 0.5f) * WALL_WIDTH, (y + 0.5f) * WALL_HEIGHT, WALL_WIDTH, WALL_HEIGHT);
						break;
					default:
						break;
				}
			}
			reader.Close();

			Dimensions = new Vector2(maxX * WALL_WIDTH, (y + 1) * WALL_HEIGHT);
		}

		public List<Wall> collisions(Vehicle vehicle)
		{
            int gridPieceCount = 0;
            List<int> gridPieceToCheck = new List<int>();
            List<Wall> crashedInto = new List<Wall>();

            foreach (FloatBox gridPiece in Grid)
            {
                if (vehicle.Box.Intersects(gridPiece))
                {
                    gridPieceToCheck.Add(gridPieceCount);
                }
                gridPieceCount++;
            }

            //checking walls in those grid pieces for crashes and sending those to Vehicle
            foreach (int pieceToCheck in gridPieceToCheck)
            {
                foreach (Wall wall in GridWalls[pieceToCheck])
                {
                    if (wall.Box.Intersects(vehicle.Box))
                    {
                        crashedInto.Add(wall);
                    }
                }
            }

            return crashedInto;
		}

		public void decreaseGameTime(double decrement)
		{
			gameData.GameTime -= decrement;
			gameData.Fooled = true;
		}
	}
}